/**
 * @file CategoryCommandImpl.java
 * Projet eCOM 2010 (Miage Descartes)
 * @author Doido Sébastien
 * @version 2
 * @brief Shell : Gestion des fonctionnalités relatives aux catégories
 */
package ecom.shell;

import ecom.beans.CategoryBean;
import ecom.beans.EcomAdminRemote;
import ecom.beans.EcomCustomerRemote;
import ecom.beans.UnknownIdentifier;
import ecom.shell.OutputCommandImpl.Outputs;
import ecom.shell.ShellConstantes.RESULT_ACTION;
import java.io.PrintStream;
import java.util.Collection;
import java.util.StringTokenizer;
import org.jdom.Attribute;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.output.Format;
import org.jdom.output.XMLOutputter;

/**
 * @brief Shell : Gestion des fonctionnalités relatives aux catégories
 * @author Sebastien
 */
public class CategoryCommandImpl implements ShellCommand {

    private ShellContext _context = null;

    public CategoryCommandImpl(ShellContext context) {
        _context = context;
    }

    /**
     * @brief Renvoie le nom de la commande
     * @return le nom de la commande
     */
    public String getName() {
        return "category";
    }

    /**
     * @brief Renvoie la manière d'utiliser la commande
     * @return la manière d'utiliser la commande
     */
    public String getUsage() {
        return "category ";
    }

    /**
     * @brief Renvoie la description de la commande
     * @return la description de la commande
     */
    public String getShortDescription() {
        String description = "List all known categories\n";
        if (true == _context.getVar("adminMode")) {
            description += "\t  : -add [name]....................create a new category\n";
            description += "\t  : -remove [categ ID].............remove a category\n";
        } 
        return description;
    }

    /**
     * @brief Exécute la commande
     * @param cmdline : commande à exécuter
     * @param out : flux d'affichage std
     * @param err : flux d'affichage err
     * @return les données à afficher
     * @throws java.lang.Exception : erreur durant l'exécution de la méthode
     */
    public String execute(String cmdline, PrintStream out, PrintStream err) throws InsuffisantPrivilege {
        StringBuffer res = new StringBuffer();
        StringTokenizer st = new StringTokenizer(cmdline, " ");

        EcomAdminRemote ecomAdminBean = (EcomAdminRemote) _context.getVar("adminBean");
        EcomCustomerRemote ecomCustomerBean = (EcomCustomerRemote) _context.getVar("customerBean");
        Outputs currentOutput = (Outputs) _context.getVar("output");
        Collection<CategoryBean> categoryList = null;

        // Ignore cmd
        st.nextToken();

        // list all known languages
        if (st.countTokens() == 0) {
            categoryList = ecomCustomerBean.getCategories();
            return printList(out, categoryList, currentOutput);
        }
        else {
            String option = st.nextToken();

            // adding
            if (option.equals("-add")) {
                if (true != _context.getVar("adminMode")) {
                    throw new InsuffisantPrivilege();
                }
                if (st.countTokens() == 1) {
                    try {
                        String name = st.nextToken();

                        int id = ecomAdminBean.createProductCategory(name);
                        res.append(_context.returnCode("Category Created with id #" + id, RESULT_ACTION.SUCCESS));
                    } catch (Exception e) {
                        res.append(_context.returnCode("Error with account creation", RESULT_ACTION.FAILED));
                        err.println("Error with account creation");
                    }
                } else {
                    res.append(_context.returnCode(Shell.INCORRECT_ARGS_NUMBER, RESULT_ACTION.FAILED));
                    err.println(Shell.INCORRECT_ARGS_NUMBER);
                }
            }
            // removing
            else if (option.equals("-remove")) {
                if (true != _context.getVar("adminMode")) {
                    throw new InsuffisantPrivilege();
                }
                if (st.countTokens() == 1) {
                    try {
                        int id = Integer.valueOf(st.nextToken());
                        ecomAdminBean.removeCategory(id);
                        res.append(_context.returnCode("Category #" + id + " deleted", RESULT_ACTION.SUCCESS));
                    } catch (UnknownIdentifier ex) {
                        res.append(_context.returnCode(ex.toString(), RESULT_ACTION.FAILED));
                        err.println(ex);
                    } catch (Exception ex) {
                        res.append(_context.returnCode(ex.toString(), RESULT_ACTION.FAILED));
                        err.println("Error with account remove" + ex);
                    }
                } else {
                    err.println(Shell.INCORRECT_ARGS_NUMBER);
                }
            }  else {
                res.append(_context.returnCode(option + " is not known for Category Management", RESULT_ACTION.FAILED));
                err.println("\t" + option + " is not known for Category Management");
            }
        }
        return res.toString();
    }

    /**
     * @brief Affichage de la liste des catégories disponibles
     * @param out : flux d'affichage std
     * @param cat : liste des catégories disponibles
     * @param currentOutput : type de sortie attendue
     * @return les données à afficher selon le type de sortie attendue
     */
    private String printList(PrintStream out, Collection<CategoryBean> cat, Outputs currentOutput) {
        StringBuffer res = new StringBuffer();
        if (currentOutput.equals(Outputs.XML)) {
            Element categories = new Element("categories");
            org.jdom.Document document = new Document(categories);

            for (CategoryBean b : cat) {
                categories.addContent(buildXMLNode(b));
            }
            XMLOutputter sortie = new XMLOutputter(Format.getPrettyFormat());
            res.append(sortie.outputString(document));
        } else if (currentOutput.equals(Outputs.TEXT)) {
            res.append("####################" + "\n");
            res.append("# Known categories #" + "\n");
            res.append("####################" + "\n");
            for (CategoryBean category : cat) {
                res.append("\t" + category + "\n");
            }
        } else {
            res.append("\t /!\\ Output format '" + currentOutput + "' is known but not implementing for this command");
        }
        return res.toString();
    }

    /**
     * @brief Construit un arbre XML pour la catégorie à afficher
     * @param cat : catégorie
     * @return un arbre XML décrivant la catégorie à afficher
     */
    private Element buildXMLNode(CategoryBean cat) {
        Element category = new Element("category");
        Attribute id = new Attribute("id", String.valueOf(cat.getIdCateg()));
        category.setAttribute(id);
        category.setText(cat.getName());
        
        return category;
    }
}
